package org.beetl.json;

import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.beetl.json.node.ArrayNode;
import org.beetl.json.node.IterableClassNode;
import org.beetl.json.node.JavaObjectNode;
import org.beetl.json.node.MapClassNode;
import org.beetl.json.node.PojoNode;



/**
 * 序列化工具
 * 
 * @author xiandafu
 *
 */
public class JsonTool {
	static Map<Class, Map<String,Policy>> cache = new ConcurrentHashMap<Class, Map<String,Policy>>();
	static Map<Class, Policy> defaultCache = new ConcurrentHashMap<Class, Policy>();
	
	static List<Location> defaultLocs = new ArrayList<Location>();
	public static boolean UseSingleQuotes  = false ;
	static Map<String,Format> formats = new HashMap<String,Format>();
	
	static List<String> parseStops = new ArrayList<String>();
	static{
		parseStops.add("java.lang.Object");
		// 还可能有些代理类??
	}
	static final String EMPTY_POLICY = "";
	
	public static boolean ignoreClientIOError = false;
	
	public static boolean pretty = false ;
	
	
	public static String serialize(Object obj){
		Policy po = getPolicy(obj.getClass(),EMPTY_POLICY);		
		try {
			return po.toJson(obj);
		} catch (IOException e) {
			//ignore
			throw new RuntimeException("不可能发生");
		}
	}
	
	public static String serialize(Object obj,String policy){
		Policy po = getPolicy(obj.getClass(),policy);
		try {
			return po.toJson(obj);
		} catch (IOException e) {
			//ignore
			throw new RuntimeException("不可能发生");
		}
	}
	
	public static void serialize(Object obj,Writer w,String policy)  {
		Policy po = getPolicy(obj.getClass(),policy);
		try {
			po.toJson(w,obj);
		} catch (IOException e) {
			if(!ignoreClientIOError)
			throw new RuntimeException(e);
		}
	}
	
	public static void serialize(Object obj,Writer w)  {
		Policy po = getPolicy(obj.getClass(),EMPTY_POLICY);
		try {
			po.toJson(w,obj);
		} catch (IOException e) {
			if(!ignoreClientIOError)
			throw new RuntimeException(e);
		}
	}
	
	public static void serializeJW(JsonWriter w,Object obj)  {
		Policy po = getPolicy(obj.getClass(),EMPTY_POLICY);
		try {
			po.toJson(w,obj);
		} catch (IOException e) {
			if(!ignoreClientIOError)
			throw new RuntimeException(e);
		}
	}

	private static Policy getPolicy(Class c,String policy) {

		if(policy==EMPTY_POLICY){
			Policy po = defaultCache.get(c);
			if(po==null){
				po = createPolicy(c,policy);
				defaultCache.put(c, po);
			}
			return po;
		}else{
			Map<String,Policy>  map= cache.get(c);
			if(map==null){
				map = new HashMap<String,Policy>();
				cache.put(c, map);
			}
			
			Policy p = map.get(policy);
			
			if (p == null) {
				
				p = createPolicy(c,policy);
				map.put(policy, p);
				
			}
			
			return p;
		}
		
	}

	/**
	 * 创建一个序列化类,使用类自己的序列化策略
	 * 
	 * @param c
	 * @param policy
	 * @return
	 */
	private static Policy createPolicy(Class c,String policy) {

		OutputNode node = null;
		Policy jsonPolicy = null;
		List<Location> spec  = null;
		if(policy!=null||policy.length()!=0){
			spec = JsonTool.parseStringPolicy(policy);
			
		}
		if (Iterable.class.isAssignableFrom(c)) {
			// java collections
			node = new IterableClassNode();
			node.setActionByLocation(defaultLocs);
			if(spec!=null){
				node.setActionByLocation(spec);
			}
		} else if(Map.class.isAssignableFrom(c)){
			node = new MapClassNode();
			node.setActionByLocation(defaultLocs);
			if(spec!=null){
				node.setActionByLocation(spec);
			}
		}else if(c.isArray()){
			node = new ArrayNode();
			node.setActionByLocation(defaultLocs);
			if(spec!=null){
				node.setActionByLocation(spec);
			}
		}
		else if (c.getPackage().getName().startsWith("java")) {
			node = new JavaObjectNode(c);
			node.setActionByLocation(defaultLocs);
			if(spec!=null){
				node.setActionByLocation(spec);
			}
		} else {
			// pojo
			PolicyParser parser = new PolicyParser();
			List<Location> list = parser.init(c);
			// 把默认的也算上
			list.addAll(defaultLocs);
			list.addAll(spec);
			node = new PojoNode(c);
			node.setActionByLocation(list);

		}

		jsonPolicy = new Policy(node);

		return jsonPolicy;
	}
	
	public static  List<Location> parseStringPolicy(String policy){
		List<Location>  list = new ArrayList<Location>();
	 	char[] chars = policy.toCharArray();
	 	int start = 0;
	 	boolean findKey = true;
	 	String key = null;
	 	String value = null;
	 	boolean paraStat = false;;
	 	for(int i=0;i<chars.length;i++){
	 		char ch = chars[i];
	 		if(findKey){
	 			if(ch==':'){
	 				findKey = false;
	 				key = new String(chars,start,i-start);
	 				start= i+1;
	 			}else{
	 				continue ;
	 			}
	 		}else{
	 			if(!paraStat){
	 				if(ch==','){
	 					findKey = true;
	 					value = new String(chars,start,i-start);
	 					start=i+1;
	 					Location location = PolicyParser.parse(null, key,value);
	 					list.add(location);
	 				}else if(ch=='/'){
	 					paraStat = true;
	 				}	 				
	 			}else if(ch=='/'){
	 				paraStat = true;
	 			}
	 		}
	 	}
	 	if(!findKey&&start!=chars.length){
	 		value = new String(chars,start,chars.length-start);
	 		Location location = PolicyParser.parse(null, key,value);
			list.add(location);
	 	}
	 	return list;
	
	}
	
	public static void addFormat(String name,Format format){
		formats.put(name, format);
	}
	
	public static  Format getFormat(String name){
		return formats.get(name);
	}

	public static void addLocationAction(String loc,String action) {		
		
		Location location = PolicyParser.parse(null, loc,action);
		defaultLocs.add(location);
	}
	
	public static void addPolicy(String policy){
		 List<Location> list = parseStringPolicy(policy);
		 defaultLocs.addAll(list);
	}
	
	public static void addParseStopClass(String  clsName){
		parseStops.add(clsName);
	}
	public static boolean  isStopParse(String  clsName){		
		return parseStops.contains(clsName);
	}

}
